package tests.com.datasentinel.utils.concurrent;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

import com.datasentinel.util.concurrent.LockDescriptor;
import com.datasentinel.util.concurrent.LockMode;
import com.datasentinel.util.concurrent.ReadWriteLockMap;

public class ReadWriteLockMap_Test
{
	@Test
	public void tryReadLock_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1234);
		long lockOwner1 = (1111);
		
		LockDescriptor lock = lockMap.tryReadLock(lockId1, lockOwner1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.READ));
		
		long lockId2 = 12344321;
		long lockOwner2 = 2222;
		
		LockDescriptor lock2 = lockMap.tryReadLock(lockId2, lockOwner2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.READ));		

		LockDescriptor lock3 = lockMap.tryReadLock(lockId1, lockOwner2);
		assertNotNull(lock3);
		assertTrue(lock3.getOwnerId() == lockOwner2);
		assertTrue(lock3.getMode().equals(LockMode.READ));
	}
	
	@Test
	public void tryWriteLock_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1234);
		long lockOwner1 = (1111);
		long unlockKey1 = (11113234234234l);
		
		LockDescriptor lock = lockMap.tryWriteLock(lockId1, lockOwner1, unlockKey1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.WRITE));
		
		long lockId2 = (12344321);
		long lockOwner2 = (2222);
		long unlockKey2 = (2222123121l);
		
		LockDescriptor lock2 = lockMap.tryWriteLock(lockId2, lockOwner2, unlockKey2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.WRITE));

		LockDescriptor lock3 = lockMap.tryWriteLock(lockId1, lockOwner2, unlockKey2);
		assertNotNull(lock3);
		assertTrue(lock3.getOwnerId() == lockOwner2);
		assertTrue(lock3.getMode().equals(LockMode.PENDING_WRITE));

		LockDescriptor lock4 = lockMap.tryWriteLock(lockId1, lockOwner2, unlockKey2);
		assertNotNull(lock4);
		assertTrue(lock3.getOwnerId() == lockOwner2);
		assertTrue(lock3.getMode().equals(LockMode.PENDING_WRITE));
	}
	
	@Test
	public void tryReadToWriteLock_SameOwner_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1234);
		long lockOwner1 = (1111);
		
		LockDescriptor lock = lockMap.tryReadLock(lockId1, lockOwner1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.READ));
		
		long unlockKey2 = (2222123121l);
		
		LockDescriptor lock2 = lockMap.tryWriteLock(lockId1, lockOwner1, unlockKey2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner1);
		assertTrue(lock2.getMode().equals(LockMode.WRITE));
	}

	@Test
	public void tryWriteToReadLock_SameOwner_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1234);
		long lockOwner1 = (1111);
		long unlockKey1 = (2222123121l);
		
		LockDescriptor lock = lockMap.tryWriteLock(lockId1, lockOwner1, unlockKey1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.WRITE));
		
		
		LockDescriptor lock2 = lockMap.tryReadLock(lockId1, lockOwner1);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner1);
		assertTrue(lock2.getMode().equals(LockMode.WRITE));
	}

	@Test
	public void tryReadToWriteLock_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1234);
		long lockOwner1 = (1111);
		
		LockDescriptor lock = lockMap.tryReadLock(lockId1, lockOwner1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.READ));
		
		long lockOwner2 = 2222;
		long unlockKey2 = (2222123121l);
		
		LockDescriptor lock2 = lockMap.tryWriteLock(lockId1, lockOwner2, unlockKey2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.PENDING_WRITE));
		
	}
	
	@Test
	public void tryWriteToReadLock_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1234);
		long lockOwner1 = (1111);
		long unlockKey1 = (2222123121l);
		
		LockDescriptor lock = lockMap.tryWriteLock(lockId1, lockOwner1, unlockKey1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.WRITE));
		
		long lockOwner2 = 2222;
		
		LockDescriptor lock2 = lockMap.tryReadLock(lockId1, lockOwner2);
		assertNotNull(lock2);
		assertFalse(lock2.getOwnerId() == lockOwner2);
	}

	
	@Test
	public void unlockWriteGetReadLock_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1234);
		long lockOwner1 = (1111);
		long unlockKey1 = (2222123121l);
		
		LockDescriptor lock = lockMap.tryWriteLock(lockId1, lockOwner1, unlockKey1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.WRITE));
		
		boolean unlocked = lockMap.unlock(lockId1, lockOwner1, unlockKey1);
		assertTrue(unlocked);
		
		long lockOwner2 = 2222;
		
		LockDescriptor lock2 = lockMap.tryReadLock(lockId1, lockOwner2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.READ));
	}

	@Test
	public void unlockWriteGetWriteLock_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1233334);
		long lockOwner1 = (1111);
		long unlockKey1 = (2222123121l);
		
		LockDescriptor lock = lockMap.tryWriteLock(lockId1, lockOwner1, unlockKey1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.WRITE));
		
		
		long lockOwner2 = 2222;
		long unlockKey2 = (2222123121234l);
		
		LockDescriptor lock2 = lockMap.tryWriteLock(lockId1, lockOwner2, unlockKey2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.PENDING_WRITE));

	
		boolean unlocked = lockMap.unlock(lockId1, lockOwner1, unlockKey2);
		assertFalse(unlocked);

		unlocked = lockMap.unlock(lockId1, lockOwner1, unlockKey1);
		assertTrue(unlocked);

		
		lock2 = lockMap.tryWriteLock(lockId1, lockOwner2, unlockKey2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.WRITE));
	}

	
	@Test
	public void unlockWriteGetCorrectPendingWriteLock_Test()
	{
		ReadWriteLockMap lockMap = new ReadWriteLockMap();
		
		long lockId1 = (1233334);
		long lockOwner1 = (1111);
		long unlockKey1 = (2222123121l);
		
		LockDescriptor lock = lockMap.tryWriteLock(lockId1, lockOwner1, unlockKey1);
		
		assertNotNull(lock);
		assertTrue(lock.getOwnerId() == lockOwner1);
		assertTrue(lock.getMode().equals(LockMode.WRITE));
		
		
		long lockOwner2 = 2222;
		long unlockKey2 = (2222123121234l);
		
		LockDescriptor lock2 = lockMap.tryWriteLock(lockId1, lockOwner2, unlockKey2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.PENDING_WRITE));

		long lockOwner3 = 333;
		long unlockKey3 = (234256123121234l);
		
		LockDescriptor lock3 = lockMap.tryWriteLock(lockId1, lockOwner3, unlockKey3);
		assertNotNull(lock3);
		assertTrue(lock3.getOwnerId() == lockOwner3);
		assertTrue(lock3.getMode().equals(LockMode.PENDING_WRITE));

		
		
		boolean unlocked = lockMap.unlock(lockId1, lockOwner1, unlockKey3);
		assertFalse(unlocked);

		unlocked = lockMap.unlock(lockId1, lockOwner1, unlockKey1);
		assertTrue(unlocked);

		
		lock3 = lockMap.tryWriteLock(lockId1, lockOwner3, unlockKey3);
		assertNotNull(lock3);
		assertTrue(lock3.getOwnerId() == lockOwner3);
		assertTrue(lock3.getMode().equals(LockMode.PENDING_WRITE));

	
		lock2 = lockMap.tryWriteLock(lockId1, lockOwner2, unlockKey2);
		assertNotNull(lock2);
		assertTrue(lock2.getOwnerId() == lockOwner2);
		assertTrue(lock2.getMode().equals(LockMode.WRITE));

		unlocked = lockMap.unlock(lockId1, lockOwner2, unlockKey2);
		assertTrue(unlocked);
	
		lock3 = lockMap.tryWriteLock(lockId1, lockOwner3, unlockKey3);
		assertNotNull(lock3);
		assertTrue(lock3.getOwnerId() == lockOwner3);
		assertTrue(lock3.getMode().equals(LockMode.WRITE));

	}

	
}
